--[[--
-- BattlefieldLocator
--
-- by Intangir (intangir.org, intangir.googlecode.com)
-- thanks to PartySpotter and BattlefieldCommander(not being updated?) for the concepts and some graphics
--
-- color codes player blips on worldmap and minimap for guildmates/friends, whos in combat/dead, also indicators for target and focus
-- 
-- this basically just tacks on an extra child frame to the existing blizzard frames for player blips on maps
-- and updates texture visibility depending on their state
-- also with target and focus it just updates which blizzard player blip is its parent

-- this way i dont have to track positions and update positions or the map myself

-- this addon requires stubby

--]]--

local aFriends = {};		-- array of friends names
local nFriends = 0;			-- number of friends
local aGuild = {};			-- array of guildmate names
local nGuild = 0;			-- number of guildmates
local nDefaultScale = 1.2;	-- scale
local _G = _G;				-- supposedly this makes it a tad faster

local nUpdateInterval = 2;	-- update states every 2 seconds
local nUpdateTimer = 0;		-- keeps time till next update

-- register events
function BattlefieldLocator_OnLoad()
	this:RegisterEvent("ADDON_LOADED");
	this:RegisterEvent("PLAYER_TARGET_CHANGED");
	this:RegisterEvent("PLAYER_FOCUS_CHANGED");
	this:RegisterEvent("FRIENDLIST_UPDATE");
	this:RegisterEvent("GUILD_ROSTER_UPDATE");
	this:RegisterEvent("PLAYER_ENTERING_WORLD");
--	this:RegisterEvent("WORLD_MAP_UPDATE");
	this:RegisterEvent("RAID_ROSTER_UPDATE");
	this:RegisterEvent("PARTY_MEMBERS_CHANGED");
end

-- handle events
function BattlefieldLocator_OnEvent()
	if ( event == "ADDON_LOADED" ) then
		if ( ( arg1 ) and ( arg1 == "BattlefieldLocator" ) ) then
			BattlefieldLocator_Load();
		end

		if ( ( arg1 ) and ( arg1 == "Blizzard_BattlefieldMinimap" ) ) then
			BattlefieldLocatorMM_Load();
		end

	elseif ( event == "PLAYER_TARGET_CHANGED" ) then
		BattlefieldLocator_UpdateTarget("Target");

	elseif ( event == "PLAYER_FOCUS_CHANGED" ) then
		BattlefieldLocator_UpdateTarget("Focus");

	elseif ( event == "FRIENDLIST_UPDATE" ) then
		BattlefieldLocator_UpdateFriends();
		BattlefieldLocator_Refresh();

	elseif ( event == "GUILD_ROSTER_UPDATE" ) then
		BattlefieldLocator_UpdateGuild();
		BattlefieldLocator_Refresh();

	elseif ( event == "PLAYER_ENTERING_WORLD" or
--		 event == "WORLD_MAP_UPDATE" or
		 event == "RAID_ROSTER_UPDATE" or 
		 event == "PARTY_MEMBERS_CHANGED" ) then
--		BattlefieldLocator_SetScale();
		BattlefieldLocator_Refresh();
	end
end

-- get the blizzard addon loaded since my functionality is all off of that
function BattlefieldLocator_Load()
	LoadAddOn("Blizzard_BattlefieldMinimap");
end

-- set up variables, menus, and blip hiearchy/visibility
function BattlefieldLocatorMM_Load()
	-- load saved variables
	if not BFL_nMapScale or type(BFL_nMapScale) ~= "number" then 
		BFL_nMapScale = nDefaultScale;
	end

	if not BFL_nBlipScale or type(BFL_nBlipScale) ~= "number" then 
		BFL_nBlipScale = nDefaultScale;
	end

	-- override default menu
	UIDropDownMenu_Initialize(BattlefieldLocatorTabDropDown, BattlefieldLocatorDropDown_Initialize, "MENU");
	BattlefieldMinimapTab:SetScript("OnClick", function() BattlefieldLocatorTab_OnClick(arg1) end);

	-- hook a sizing function
	hooksecurefunc("BattlefieldMinimap_Update", BattlefieldLocator_SetScale);

	local fMinimap;
	local fMinimapParent;
	local fWorldmap;
	local fWorldmapParent;

	for i=1, MAX_PARTY_MEMBERS do
		fMinimapParent = _G["BattlefieldMinimapParty"..i];
		fWorldmapParent = _G["WorldMapParty"..i];

		fMinimap = CreateFrame("Frame", "fMMParty"..i, fMinimapParent, "BlipTemplate");
		fWorldmap = CreateFrame("Frame", "fWMParty"..i, fWorldmapParent, "BlipTemplate");
		
		fMinimap:SetPoint("CENTER", fMinimapParent, "CENTER", 0, 0);
		fWorldmap:SetPoint("CENTER", fWorldmapParent, "CENTER", 0, 0);

--		fMinimap:SetFrameLevel( fMinimapParent:GetFrameLevel() + 2 );
--		fWorldmap:SetFrameLevel( fWorldmapParent:GetFrameLevel() + 2 );

		fMinimap:Show();
		fWorldmap:Show();
	end

	for i=1, MAX_RAID_MEMBERS do
		fMinimapParent = _G["BattlefieldMinimapRaid"..i];
		fWorldmapParent = _G["WorldMapRaid"..i];

		fMinimap = CreateFrame("Frame", "fMMRaid"..i, fMinimapParent, "BlipTemplate");
		fWorldmap = CreateFrame("Frame", "fWMRaid"..i, fWorldmapParent, "BlipTemplate");
		
		fMinimap:SetPoint("CENTER", fMinimapParent, "CENTER", 0, 0);
		fWorldmap:SetPoint("CENTER", fWorldmapParent, "CENTER", 0, 0);

--		fMinimap:SetFrameLevel( fMinimapParent:GetFrameLevel() + 2 );
--		fWorldmap:SetFrameLevel( fWorldmapParent:GetFrameLevel() + 2 );

		fMinimap:Show();
		fWorldmap:Show();
	end

	fMMTargetOverlay:Show();
	fMMTargetOverlay:SetTexture("Interface\\AddOns\\BattlefieldLocator\\images\\target");

	fMMFocusOverlay:Show();
	fMMFocusOverlay:SetTexture("Interface\\AddOns\\BattlefieldLocator\\images\\focus");

	fWMTargetOverlay:Show();
	fWMTargetOverlay:SetTexture("Interface\\AddOns\\BattlefieldLocator\\images\\target");

	fWMFocusOverlay:Show();
	fWMFocusOverlay:SetTexture("Interface\\AddOns\\BattlefieldLocator\\images\\focus");

	-- get friends list
	ShowFriends();

	-- get guild list
	GuildRoster();

end

-- handles click on the tab for the blizzard battlefield minimap
function BattlefieldLocatorTab_OnClick(button)
	-- If Rightclick bring up the options menu
	if ( button == "RightButton" ) then
		ToggleDropDownMenu(1, nil, BattlefieldLocatorTabDropDown, this:GetName(), 0, 0);
		return;
	end

	-- Close all dropdowns
	CloseDropDownMenus();

	-- If frame is not locked then allow the frame to be dragged or dropped
	if ( this:GetButtonState() == "PUSHED" ) then
		BattlefieldMinimapTab:StopMovingOrSizing();
	else
		-- If locked don't allow any movement
		if ( BattlefieldMinimapOptions.locked ) then
			return;
		else
			BattlefieldMinimapTab:StartMoving();
		end
	end
	ValidateFramePosition(BattlefieldMinimapTab);

	PlaySound("UChatScrollButton");
end

-- set up the menu for the minimap
function BattlefieldLocatorDropDown_Initialize()
	local checked;
	local info = UIDropDownMenu_CreateInfo();
	-- Show battlefield players
	info.text = SHOW_BATTLEFIELDMINIMAP_PLAYERS;
	info.func = BattlefieldMinimap_TogglePlayers;
	info.checked = BattlefieldMinimapOptions.showPlayers;
	UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
	
	-- Battlefield minimap lock
	info.text = LOCK_BATTLEFIELDMINIMAP;
	info.func = BattlefieldMinimap_ToggleLock;
	info.checked = BattlefieldMinimapOptions.locked;
	UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);

	-- Opacity
	info.text = BATTLEFIELDMINIMAP_OPACITY_LABEL;
	info.func = BattlefieldMinimap_ShowOpacity;
	info.checked = nil;
	UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);

	-- map Scale
	info.text = "Change Map Scale";
	info.func = BattlefieldLocator_ShowMapScale;
	info.checked = nil;
	UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);

	-- blip Scale
	info.text = "Change Blip Scale";
	info.func = BattlefieldLocator_ShowBlipScale;
	info.checked = nil;
	UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);

end

-- handle click for mapscale menu option
function BattlefieldLocator_ShowMapScale()
	ScaleFrame:ClearAllPoints();
	ScaleFrame:SetPoint("TOPRIGHT", "BattlefieldMinimap", "TOPLEFT", 0, 7);
	ScaleFrame.scaleFunc = BattlefieldLocator_NewMapScale;
	ScaleFrame:Show();
	ScaleFrameSlider:SetValue( BFL_nMapScale );
end

-- handle click for blipscale menu option
function BattlefieldLocator_ShowBlipScale()
	ScaleFrame:ClearAllPoints();
	ScaleFrame:SetPoint("TOPRIGHT", "BattlefieldMinimap", "TOPLEFT", 0, 7);
	ScaleFrame.scaleFunc = BattlefieldLocator_NewBlipScale;
	ScaleFrame:Show();
	ScaleFrameSlider:SetValue( BFL_nBlipScale );
end

-- pops up scaling option dlg for map scale
function BattlefieldLocator_NewMapScale()
	BFL_nMapScale = ScaleFrameSlider:GetValue();
	BattlefieldLocator_SetScale();
end

-- pops up scaling option dlg for blip scale
function BattlefieldLocator_NewBlipScale()
	BFL_nBlipScale = ScaleFrameSlider:GetValue();
	BattlefieldLocator_SetScale();
end

-- changes the scaling for map and blips
function BattlefieldLocator_SetScale()
	BattlefieldMinimap:SetScale( BFL_nMapScale );

	local nScaling = BFL_nBlipScale / BFL_nMapScale;

	for i=1, MAX_PARTY_MEMBERS do
		BattlefieldLocator_ResizeBlip( _G["BattlefieldMinimapParty"..i], 12 * nScaling);
		_G["fMMParty"..i]:SetScale(0.75 * nScaling);
	end

	for i=1, MAX_RAID_MEMBERS do
		BattlefieldLocator_ResizeBlip( _G["BattlefieldMinimapRaid"..i], 12 * nScaling);
		_G["fMMRaid"..i]:SetScale(0.75 * nScaling);
	end

	for i=1, GetNumMapLandmarks() do
		BattlefieldLocator_ResizeBlip( _G["BattlefieldMinimapPOI"..i], 12 * nScaling);
	end

	BattlefieldLocator_ResizeBlip(BattlefieldMinimapFlag1, 18 * nScaling);
	BattlefieldLocator_ResizeBlip(BattlefieldMinimapFlag2, 18 * nScaling);

	fMMTarget:SetScale(0.9 * nScaling);
	fMMFocus:SetScale(0.9 * nScaling);

end

-- tiny helper function to change blip metrics
function BattlefieldLocator_ResizeBlip(fBlip, nSize)
	fBlip:SetWidth(nSize);
	fBlip:SetHeight(nSize);
end

-- checks if enough time has passed to need a refresh
function BattlefieldLocator_OnUpdate(nElapsed)
	nUpdateTimer = nUpdateTimer - nElapsed;
	if (nUpdateTimer < 0) then
		BattlefieldLocator_Refresh();
	end
end

-- updates the status (which artwork shows) of the blips
function BattlefieldLocator_Refresh()
	nUpdateTimer = nUpdateInterval;
	BattlefieldLocator_UpdateTarget("Target");
	BattlefieldLocator_UpdateTarget("Focus");

	local szUnit;
	local nNeedIcon;

	local nRaid = GetNumRaidMembers();
	if ( nRaid > 0 ) then
		for i=1, nRaid do
			szUnit = "Raid"..i;
			nNeedIcon = BattlefieldLocator_SetBlipState("Raid"..i, "Dead", UnitIsDeadOrGhost(szUnit) );
			nNeedIcon = BattlefieldLocator_SetBlipState("Raid"..i, "Combat", nNeedIcon > 0 and UnitAffectingCombat(szUnit) ) * nNeedIcon;
			nNeedIcon = BattlefieldLocator_SetBlipState("Raid"..i, "Friend", nNeedIcon > 0 and aFriends[UnitName(szUnit)] ) * nNeedIcon;
			nNeedIcon = BattlefieldLocator_SetBlipState("Raid"..i, "Guild", nNeedIcon > 0 and aGuild[UnitName(szUnit)] ) * nNeedIcon;
		end
	else
		for i=1, GetNumPartyMembers() do
			szUnit = "Party"..i;
			nNeedIcon = BattlefieldLocator_SetBlipState("Party"..i, "Dead", UnitIsDeadOrGhost(szUnit) );
			nNeedIcon = BattlefieldLocator_SetBlipState("Party"..i, "Combat", nNeedIcon > 0 and UnitAffectingCombat(szUnit) ) * nNeedIcon;
			nNeedIcon = BattlefieldLocator_SetBlipState("Party"..i, "Friend", nNeedIcon > 0 and aFriends[UnitName(szUnit)] ) * nNeedIcon;
			nNeedIcon = BattlefieldLocator_SetBlipState("Party"..i, "Guild", nNeedIcon > 0 and aGuild[UnitName(szUnit)] ) * nNeedIcon;
		end
	end
end

-- sets visibility of the texture depending on the state flag
function BattlefieldLocator_SetBlipState(szGroup, szTexture, nState)
	tMinimap = _G["fMM"..szGroup..szTexture];
	tWorldmap = _G["fWM"..szGroup..szTexture];
	
	if ( nState ) then
		tMinimap:Show();
		tWorldmap:Show();
		return 0;
	else
		tMinimap:Hide();
		tWorldmap:Hide();
		return 1;
	end
end

-- changes the parent of the target/focus graphics if your target/focus have changed
function BattlefieldLocator_UpdateTarget(changed)
	local fMMBlip = _G["fMM"..changed];
	local fWMBlip = _G["fWM"..changed];
	if( not UnitExists(changed) ) then
		fMMBlip:Hide();
		fWMBlip:Hide();
		return;
	end

	local unitButton ;
	
	-- Check Raid
	for i=1, GetNumRaidMembers() do
		unitButton = _G["BattlefieldMinimapRaid"..i];
		if ( UnitIsUnit(unitButton.unit, changed) ) then
			fMMBlip:SetParent(unitButton);
			fMMBlip:SetPoint("CENTER", unitButton, "CENTER", 0, 0);
			fMMBlip:SetFrameLevel(unitButton:GetFrameLevel() + 100 );
			fMMBlip:Show();

			unitButton = _G["WorldMapRaid"..i];
			fWMBlip:SetParent(unitButton);
			fWMBlip:SetPoint("CENTER", unitButton, "CENTER", 0, 0);
			fWMBlip:SetFrameLevel(unitButton:GetFrameLevel() + 100 );
			fWMBlip:Show();
			return;
		end
	end

	-- Check party
	for i=1, GetNumPartyMembers() do
		unitButton = _G["BattlefieldMinimapParty"..i];
		if ( UnitIsUnit(unitButton.unit, changed) ) then
			fMMBlip:SetParent(unitButton);
			fMMBlip:SetPoint("CENTER", unitButton, "CENTER", 0, 0);
			fMMBlip:SetFrameLevel(unitButton:GetFrameLevel() + 100 );
			fMMBlip:Show();

			unitButton = _G["WorldMapParty"..i];
			fWMBlip:SetParent(unitButton);
			fWMBlip:SetPoint("CENTER", unitButton, "CENTER", 0, 0);
			fWMBlip:SetFrameLevel(unitButton:GetFrameLevel() + 100 );
			fWMBlip:Show();
			return;
		end
	end

	-- if its still not found your focus/target then just hide it
	fMMBlip:Hide();
	fWMBlip:Hide();

end

-- saves the friends names into local vars
function BattlefieldLocator_UpdateFriends()
	aFriends = {};
	nFriends = 0;
	for i = 1, GetNumFriends(), 1 do
		local fName = GetFriendInfo(i);
		if ( ( fName ) and ( fName ~= "" ) ) then
			aFriends[fName] = "1";
			nFriends = nFriends + 1;
		end
	end
end

-- saves the guildnames into local var
function BattlefieldLocator_UpdateGuild()
	aGuild = {};
	nGuild = 0;
	if ( GetGuildInfo("player") ) then
		for i = 1, GetNumGuildMembers(), 1 do
			local gName = GetGuildRosterInfo(i);
			if ( ( gName ) and ( gName ~= "" ) ) then
				aGuild[gName] = "1";
				nGuild = nGuild + 1;
			end
		end
	end
end

